#pragma once

#include <string>
#include <list>
#include <vector>
#include <unordered_map>

class JsonBuilder;
class Parser;

extern void split(const std::string& src, const std::string& delim,
    std::vector<std::string>& result);
extern std::string trim(const std::string& src, const std::string& delim);

/// Output type
enum class OutputType {
    NONE = 0,
    CPP = 1,
    PB,
    CSHARP,
    GOLANG,
    IDL,
    ALL,
};

// Json generator frontend
class Frontend {
    std::string file_; ///< Current file need to generate
    std::string shortFileName_; ///< Short file name like: a.txt
    std::string typeOptionFile_; ///< Option file, reserved
    std::string outputDir_ {std::string(".")}; ///< Output directory
    OutputType type_ {OutputType::NONE}; ///< Output type
    bool onlyCheck_ {false}; ///< Only check IDL file
    std::unordered_map<std::uint64_t, std::string> uuids_; ///< UUID database
    std::string uuidDbFileName_; ///< UUID database file name
    std::string dependDbFileName_; ///< Dependency database file name
    using DependencyMap = std::unordered_map<std::string, std::list<std::string>>;
    DependencyMap dependency_; ///< Dependency

public:
    // Parse command line and build
    // @retval 0 success
    // @retval 1 failure
    int startup(int argc, const char** argv);
    // Create a new UUID for service
    // @param fileName current file name
    // @param serviceName service name
    // @return UUID string
    std::string makeServiceUUID(const std::string& fileName,
        const std::string& serviceName);
    /**
     * @brief Update imported file
     * @param importedFileName imported file name
     * @return true or false
    */
    bool updateDependency(const std::string& importedFileName);

    std::string concatPath(const std::string& root,
                                     const std::string& child);

private:
    // Write JSON file
    // @param parser Parser
    // @param builder JSON builder
    void writeJsonFile(Parser& parser, JsonBuilder& builder);
    // Load UUID database
    bool loadUUIDDatabase();
    // Update UUID database
    void writeUUIDDatabase();
    // Build dependency database
    bool loadDependencyDatabase();
    // Update dependency database
    void writeDependencyDatabase();
    std::string getShortName(const std::string& fileName);
    bool checkDependency(const std::string& shortName);
};
